{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## MNIST Image Classification with an MLP Model\n",
    "\n",
    "### Build the dataset and dataloader"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Downloading http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz\n",
      "Failed to download (trying next):\n",
      "HTTP Error 403: Forbidden\n",
      "\n",
      "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/train-images-idx3-ubyte.gz\n",
      "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/train-images-idx3-ubyte.gz to ./data/MNIST/raw/train-images-idx3-ubyte.gz\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████| 9912422/9912422 [00:03<00:00, 2979030.58it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting ./data/MNIST/raw/train-images-idx3-ubyte.gz to ./data/MNIST/raw\n",
      "\n",
      "Downloading http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz\n",
      "Failed to download (trying next):\n",
      "HTTP Error 403: Forbidden\n",
      "\n",
      "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/train-labels-idx1-ubyte.gz\n",
      "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/train-labels-idx1-ubyte.gz to ./data/MNIST/raw/train-labels-idx1-ubyte.gz\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████| 28881/28881 [00:00<00:00, 129753.95it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting ./data/MNIST/raw/train-labels-idx1-ubyte.gz to ./data/MNIST/raw\n",
      "\n",
      "Downloading http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz\n",
      "Failed to download (trying next):\n",
      "HTTP Error 403: Forbidden\n",
      "\n",
      "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-images-idx3-ubyte.gz\n",
      "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-images-idx3-ubyte.gz to ./data/MNIST/raw/t10k-images-idx3-ubyte.gz\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████| 1648877/1648877 [00:01<00:00, 1260129.41it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting ./data/MNIST/raw/t10k-images-idx3-ubyte.gz to ./data/MNIST/raw\n",
      "\n",
      "Downloading http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz\n",
      "Failed to download (trying next):\n",
      "HTTP Error 403: Forbidden\n",
      "\n",
      "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-labels-idx1-ubyte.gz\n",
      "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-labels-idx1-ubyte.gz to ./data/MNIST/raw/t10k-labels-idx1-ubyte.gz\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████| 4542/4542 [00:00<00:00, 17989167.86it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting ./data/MNIST/raw/t10k-labels-idx1-ubyte.gz to ./data/MNIST/raw\n",
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    "import torchvision\n",
    "from torchvision import transforms\n",
    "\n",
    "# Define the transformations to apply to the data\n",
    "transform = transforms.Compose([\n",
    "    transforms.ToTensor(),\n",
    "    transforms.Normalize((0.5,), (0.5,))\n",
    "])\n",
    "\n",
    "# Load the MNIST dataset\n",
    "train_dataset = torchvision.datasets.MNIST(root='./data', train=True, download=True, transform=transform)\n",
    "test_dataset = torchvision.datasets.MNIST(root='./data', train=False, download=True, transform=transform)\n",
    "\n",
    "# Create the data loaders\n",
    "batch_size = 64\n",
    "train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True)\n",
    "test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=batch_size, shuffle=False)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Visualize samples from the dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAA8gAAAPdCAYAAABWSUEqAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAAA9hAAAPYQGoP6dpAABifUlEQVR4nO3debyWZZ0/8M9hTYFUwJQlgQ4parmPuUS4VGparqNjNmqoQ7mXS/0UQ1HStMV0MjdCU6cczNzNNEnNHJdMJ0lSLEwtyCVSVDZ5fn/0ipH0vs7x4ezn/X69+MPzeb73fZ2DF5wPNzxXQ61WqwUAAAC6uR7tvQAAAADoCBRkAAAAiIIMAAAASRRkAAAASKIgAwAAQBIFGQAAAJIoyAAAAJBEQQYAAIAkCjIAAAAkUZBb1GWXXZaGhoY89NBDLXK9hoaGHHnkkS1yrTdf89RTT22Ra91xxx1paGhIQ0NDXnjhhRa5JnQ0XX1fn3rqqcv38dv9+OEPf9iia4WOoKvv6ySZOHFidttttwwbNiwNDQ05+OCDW2xt0BHZ17QUBZm6LFiwIIcddliGDh3a3ksBVsKhhx6a++677y0/PvCBD2SVVVbJzjvv3N5LBOrwrW99Ky+++GI+9alPpU+fPu29HKAF2Ndto1d7L4DO6ctf/nLWWGON7LrrrjnjjDPaezlAnYYPH57hw4ev8LE5c+Zk5syZOeCAA7L66qu3z8KAlfLKK6+kR4+/Pwe54oor2nk1QEuwr9uGJ8htbOHChTnuuOOyySabZLXVVsvAgQOz9dZb5/rrr6+cueiii7Luuuumb9++2WCDDd72rzzOnTs3EyZMyPDhw9OnT5+MGjUqp512WpYuXdrin8M999yTiy++OJdeeml69uzZ4teHzqYr7Os3+973vpdarZZDDz20Ve8DHVln39f/+CYa+D/2Nc3hCXIbW7RoUV566aUcf/zxGTZsWBYvXpw77rgje+21V6ZNm5YDDzxwhdffcMMNmTFjRiZPnpx+/frlggsuyP77759evXpln332SfL3TbnlllumR48e+cpXvpLGxsbcd999OeOMMzJnzpxMmzatuKaRI0cm+ftTo6a8/vrrOeSQQ3Lsscdms802yw033FDX1wG6ks6+r99s2bJlueyyyzJ69OiMGzfuHc1CV9KV9jXwd/Y1zVKjxUybNq2WpPbggw82e2bp0qW1JUuW1A455JDapptuukKWpLbKKqvU5s6du8Lrx4wZUxs9evTyj02YMKHWv3//2tNPP73C/Ne//vVaktrMmTNXuOakSZNWeF1jY2OtsbGxWes97rjjau973/tqr732Wq1Wq9UmTZpUS1J7/vnnmzUPnU132Ndvduutt9aS1M4888x3PAudRXfb1/369asddNBB73gOOhP7mpbiOX07mD59erbddtv0798/vXr1Su/evTN16tQ8/vjjb3ntjjvumLXWWmv5f/fs2TP77bdfZs+enWeffTZJctNNN2X77bfP0KFDs3Tp0uU/dtlllyTJXXfdVVzP7NmzM3v27CbX/cADD+Tcc8/NRRddlFVWWeWdfMrQ5XXWff3Ppk6dml69enlnTEjX2dfA/7GvaYqC3Mauvfba7Lvvvhk2bFiuvPLK3HfffXnwwQczfvz4LFy48C2vX3vttSs/9uKLLyZJ5s2blxtvvDG9e/de4ceGG26YJC12BNP48eOz1157ZYsttsj8+fMzf/785Wt++eWX88orr7TIfaCz6cz7+s1eeOGF3HDDDdl1113fdo3QnXSVfQ38H/ua5vBvkNvYlVdemVGjRuXqq69OQ0PD8o8vWrTobV8/d+7cyo8NGjQoSTJ48OBstNFGmTJlytteo6WOYpo5c2ZmzpyZ6dOnvyVrbGzMxhtvnEceeaRF7gWdSWfe1292xRVXZPHixd6cC9J19jXwf+xrmkNBbmMNDQ3p06fPCpty7ty5le+e97Of/Szz5s1b/tc73njjjVx99dVpbGxcfjTLbrvtlltuuSWNjY1ZY401Wm3tM2bMeMvHLrvsslx++eW57rrrMmzYsFa7N3RknXlfv9nUqVMzdOjQ5X8tDLqzrrKvgf9jX9McCnIruPPOO9/2neg+8YlPZLfddsu1116bww8/PPvss0+eeeaZnH766RkyZEiefPLJt8wMHjw4O+ywQ0455ZTl7543a9asFd5ifvLkybn99tuzzTbb5Oijj856662XhQsXZs6cObnlllty4YUXvuWc0zcbPXp0kjT57x+22267t3zs5z//eZJk2223zeDBg4vz0Jl11X39D/fff39mzpyZk046yfFtdBtdeV/fddddef7555P8/Zv6p59+Otdcc02SZNy4cVlzzTWbvAZ0RvY1K6293yWsK/nHu+dV/fjDH/5Qq9Vq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pUuXttq9oTM4++yz2+W+8+bNK+bz589vm4VAJ7TjjjsW86Z+76vXn/70p2L+/PPPt8p9aXmeIAMAAEAUZAAAAEiiIAMAAEASBRkAAACSKMgAAACQREEGAACAJAoyAAAAJHEOcqez6qqrVmZNnXPc0NBQzO+555661gSU9ehR/rPIXXfdtTLr16/fSt37f/7nfyqzO+64Y6WuDQAdzSqrrFLM+/TpU/e1L7/88srsvPPOK846B7nz8AQZAAAAoiADAABAEgUZAAAAkijIAAAAkERBBgAAgCQKMgAAACRxzFOnM3bs2Mps0KBBxdnHH3+8mM+aNauuNQFlY8aMKeZnnnlm3ddesmRJMf/+979fmb3xxht13xe6gg9/+MPF/P3vf38brWRFU6dObZf7Qlfw7LPPFvMXX3yxMhsyZEhx9je/+U1l9uijj5YXRqfhCTIAAABEQQYAAIAkCjIAAAAkUZABAAAgiYIMAAAASRRkAAAASKIgAwAAQBLnIHc6J510UmXW0NBQnG3qnOM111yzMnv66afLCwMqTZw4sdWufeGFFxbziy66qNXuDZ3d6NGji/nQoUNb5b6/+MUvivm9997bKveF7uCGG24o5q21r+k6PEEGAACAKMgAAACQREEGAACAJAoyAAAAJFGQAQAAIImCDAAAAEkc89TprLfeepVZrVYrzu6xxx7F/C9/+Utl9vnPf744C93dwQcfXJntt99+rXbf66+/vtWuDV3doEGDivmyZcta5b5Tp05tletCdzFu3LjK7K677irOfvzjH6/Mmvo1ge7BE2QAAACIggwAAABJFGQAAABIoiADAABAEgUZAAAAkijIAAAAkERBBgAAgCTOQe50evSo/jONps5rfO2114r5t7/97brWBN3BgAEDivkXv/jFVrnvl7/85WL+i1/8olXuC93B2WefXcxb6xxkYOWUzjpesGBBcXajjTaqzPr371+c/fOf/1xeGF2CJ8gAAAAQBRkAAACSKMgAAACQREEGAACAJAoyAAAAJFGQAQAAIIljnjqd0pETtVqtOHvggQcW81mzZtW1JugOvvKVrxTzDTfcsFXuWzrKIkmWLFnSKvcFVs78+fMrs7lz57bdQqCbWXvttYt5nz59KrMnn3yyOHv11VfXtSY6F0+QAQAAIAoyAAAAJFGQAQAAIImCDAAAAEkUZAAAAEiiIAMAAEASBRkAAACSJA21pg7P/ccLGxpaey3QLTRzy7UJ+3pFQ4YMqcyeeeaZ4uzKfC2/9a1vVWYnnHBCcbYj/f/UnXWknwf7uvkuuuiiYj5+/Pi6r106w/yjH/1o3del7djXXdNVV11VmU2aNKk4O3v27JZeDm2sOfvaE2QAAACIggwAAABJFGQAAABIoiADAABAEgUZAAAAkijIAAAAkMQxT9DmHBvRcX35y1+uzKZMmVL3dV999dVivv7661dmzz33XN33pe3Y19D12NfQ9TjmCQAAAJpJQQYAAIAoyAAAAJBEQQYAAIAkCjIAAAAkUZABAAAgiYIMAAAASZJe7b0AgK5uyZIlxdxZxwAAHYMnyAAAABAFGQAAAJIoyAAAAJBEQQYAAIAkCjIAAAAkUZABAAAgSdJQq9VqzXphQ0NrrwW6hWZuuTZhX0PLsK+h67Gvoetpzr72BBkAAACiIAMAAEASBRkAAACSKMgAAACQREEGAACAJAoyAAAAJFGQAQAAIMk7OAcZAAAAujJPkAEAACAKMgAAACRRkAEAACCJggwAAABJFGQAAABIoiADAABAEgUZAAAAkijIAAAAkERBBgAAgCQKMgAAACRRkAEAACCJggwAAABJFGQAAABIoiADAABAEgUZAAAAkijILeqyyy5LQ0NDHnrooRa5XkNDQ4488sgWudabr3nqqafWPT9x4sTstttuGTZsWBoaGnLwwQe32NqgI+rq+/pXv/pVjjjiiHzwgx/MgAEDstZaa+WjH/1o7rzzzhZdI3QkXX1f/8Njjz2Wf/3Xf82aa66Zvn37ZuTIkTn88MNbZoHQwXSHfe378LahIPOOfOtb38qLL76YT33qU+nTp097LwdYST/4wQ/ywAMPZPz48bn++utz6aWXpm/fvtlxxx3z/e9/v72XB9RpxowZ2XLLLfPyyy/nwgsvzE9/+tOcfvrpede73tXeSwPq5PvwttGrvRdA5/LKK6+kR4+//7nKFVdc0c6rAVbWiSeemK9//esrfOwTn/hENttss0yePDkHHnhgO60MqNdrr72WAw44IDvssENuvPHGNDQ0LM/+/d//vR1XBqwM34e3DU+Q29jChQtz3HHHZZNNNslqq62WgQMHZuutt871119fOXPRRRdl3XXXTd++fbPBBhvkhz/84VteM3fu3EyYMCHDhw9Pnz59MmrUqJx22mlZunRpi67/H5sS+D+deV+/5z3vecvHevbsmc033zzPPPNMi90HOpvOvK+nT5+eP//5zznhhBNWKMfQ3XXmfZ34PryteILcxhYtWpSXXnopxx9/fIYNG5bFixfnjjvuyF577ZVp06a95WnNDTfckBkzZmTy5Mnp169fLrjgguy///7p1atX9tlnnyR/35RbbrllevToka985StpbGzMfffdlzPOOCNz5szJtGnTimsaOXJkkmTOnDmt8SlDl9fV9vXSpUtzzz33ZMMNN3zHs9BVdOZ9fffddydJ3njjjXz4wx/OAw88kH79+mXnnXfON77xjQwdOrS+Lwp0cp15X9OGarSYadOm1ZLUHnzwwWbPLF26tLZkyZLaIYccUtt0001XyJLUVlllldrcuXNXeP2YMWNqo0ePXv6xCRMm1Pr37197+umnV5j/+te/XktSmzlz5grXnDRp0gqva2xsrDU2NjZ7zf/Qr1+/2kEHHfSO56Az6W77ular1U4++eRaktp1111X1zx0dF19X++00061JLXVV1+9duKJJ9buvPPO2oUXXlgbNGhQbfTo0bVXX3212Z83dBZdfV//M9+Htx7P6dvB9OnTs+2226Z///7p1atXevfunalTp+bxxx9/y2t33HHHrLXWWsv/u2fPntlvv/0ye/bsPPvss0mSm266Kdtvv32GDh2apUuXLv+xyy67JEnuuuuu4npmz56d2bNnt+BnCN1PV9nXl156aaZMmZLjjjsuu++++zueh66ks+7rZcuWJUn222+/fO1rX8v222+fCRMmZOrUqZk9e3b+67/+q9lfA+hqOuu+pu0oyG3s2muvzb777pthw4blyiuvzH333ZcHH3ww48ePz8KFC9/y+rXXXrvyYy+++GKSZN68ebnxxhvTu3fvFX78469HvvDCC634GQFdZV9PmzYtEyZMyH/8x3/knHPOafHrQ2fSmff1oEGDkiQ77bTTCh/faaed0tDQkIcffrhF7gOdTWfe17Qd/wa5jV155ZUZNWpUrr766hXeOGPRokVv+/q5c+dWfuwfvwEOHjw4G220UaZMmfK21/BvjaB1dYV9PW3atBx66KE56KCDcuGFF3pjH7q9zryvN9poo7d9I6F/8EY/dFedeV/TdhTkNtbQ0JA+ffqssCnnzp1b+e55P/vZzzJv3rzlf73jjTfeyNVXX53GxsYMHz48SbLbbrvllltuSWNjY9ZYY43W/ySAFXT2fX3ZZZfl0EMPzWc+85lceumlyjGkc+/rPffcMyeffHJuvfXW7Lnnnss/fuutt6ZWq2WrrbZqtXtDR9aZ9zVtR0FuBXfeeefbvhPdJz7xiey222659tprc/jhh2efffbJM888k9NPPz1DhgzJk08++ZaZwYMHZ4cddsgpp5yy/N3zZs2atcKfDE+ePDm33357ttlmmxx99NFZb731snDhwsyZMye33HJLLrzwwuWb+O2MHj06SZr17x/uuuuuPP/880n+/ovE008/nWuuuSZJMm7cuKy55ppNXgM6o666r6dPn55DDjkkm2yySSZMmJAHHnhghXzTTTdN3759i9eAzqqr7usxY8bkiCOOyAUXXJABAwZkl112yRNPPJGJEydm0003zb777tvMrxB0Pl11Xye+D28z7f0uYV3JP949r+rHH/7wh1qtVqudddZZtZEjR9b69u1bW3/99WuXXHJJbdKkSbV//ulIUjviiCNqF1xwQa2xsbHWu3fv2pgxY2pXXXXVW+79/PPP144++ujaqFGjar17964NHDiwtvnmm9dOPvnk2oIFC1a45j+/e96IESNqI0aMaNbnOG7cuMrPb8aMGe/kywWdQlff1wcddFCzPj/oSrr6vq7V/v5uu2eddVZt9OjRtd69e9eGDBlS+/znP1/761//+k6+VNBpdId97fvwttFQq9VqLdS1AQAAoNPyLg0AAAAQBRkAAACSKMgAAACQREEGAACAJAoyAAAAJFGQAQAAIImCDAAAAEmSXs19YUNDQ2uuA7qNjnT0uH0NLcO+hq7Hvoaupzn72hNkAAAAiIIMAAAASRRkAAAASKIgAwAAQBIFGQAAAJIoyAAAAJBEQQYAAIAkCjIAAAAkUZABAAAgiYIMAAAASRRkAAAASKIgAwAAQBIFGQAAAJIoyAAAAJBEQQYAAIAkCjIAAAAkUZABAAAgiYIMAAAASRRkAAAASKIgAwAAQBIFGQAAAJIkvdp7AQAAtL9NNtmkmF9zzTWVWWNjY3H2i1/8YmX2rW99qzgL0JY8QQYAAIAoyAAAAJBEQQYAAIAkCjIAAAAkUZABAAAgiYIMAAAASRzz1OEccMABxfzKK6+szJ599tni7Mc+9rFiPmvWrGIOAHRsAwcOLOaHHnpoZTZlypTibI8e1c9Vzj///OLstddeW8yB9lGr1Sqziy++uDh79NFHV2aLFi2qe03tzRNkAAAAiIIMAAAASRRkAAAASKIgAwAAQBIFGQAAAJIoyAAAAJBEQQYAAIAkzkHucDbffPNivmzZssps6NChxdlNN920mDsHme5u+PDhlVmvXvX/crl06dJi3tQZ5kD3UjpvOEk+/OEPV2b77LNPcfaII46ozObPn1+cLV373nvvLc4uXry4mAOto6l+UOoWhxxySHF22rRpldn//M//lBfWgXmCDAAAAFGQAQAAIImCDAAAAEkUZAAAAEiiIAMAAEASBRkAAACSOOapw/nXf/3Xumd/+9vfFvObb7657mtDV7DddtsV82uuuaYyW2211YqzpWNZ/vrXvxZnzz///Mrs29/+dnG2qWNZgI6ndKRckpx99tnFfL/99qvMXnvtteLs9OnTK7PPfOYzxdmmjqwD2sfnPve5yuzEE09sw5V0DZ4gAwAAQBRkAAAASKIgAwAAQBIFGQAAAJIoyAAAAJBEQQYAAIAkCjIAAAAkcQ5yh3PhhRcW88mTJ1dmI0aMKM5uueWWxfyOO+4o5tDZjRs3rpg3ddZxvZq67sSJEyuz8ePHF2cvvvjiYj5lypRiDrSOjTfeuDK79dZbi7NrrbVWMV+0aFFldu655xZnTznllGIOdDxDhw4t5qWzjtdZZ52673vJJZcU84cffrjua3dkniADAABAFGQAAABIoiADAABAEgUZAAAAkijIAAAAkERBBgAAgCSOeepwfv/739c9269fv2K+3nrrFXPHPNHVXX/99cX885//fGU2aNCgll5OszR1tMOpp55azOfNm1eZXXrppfUsCbqNnj17VmZN7b2jjjqqMhswYEBxdunSpcX8wAMPrMyuueaa4izQ+TR1fFtTR72WPPfcc5XZt771reLs4sWL675vR+YJMgAAAERBBgAAgCQKMgAAACRRkAEAACCJggwAAABJFGQAAABIoiADAABAkqShVqvVmvXChobWXgtJ9t9//2J+5ZVX1n3tp556qpivu+66dV+b5mvmlmsT9vWKrrjiisrs05/+dHG2R4/qP29ctmxZ3WtaWaV1bbfddsXZu+66q4VX03XZ113TCSecUJmdddZZdV/3tddeK+bjx48v5tOnT6/73jSffU1b+vjHP16ZXXLJJcXZYcOG1X3fDTbYoDJ74okn6r5uR9Wcfe0JMgAAAERBBgAAgCQKMgAAACRRkAEAACCJggwAAABJFGQAAABIkvRq7wXQdiZNmtTeS4AO7aijjqrMmjpiYdttt63MDjnkkOLs6quvXpmtttpqxdmV0ZGOMIH2sNFGGxXzL37xi3Vfe8GCBZXZRz7ykeLso48+Wvd9gc7p1ltvrcxW5vfr008/vZh3xaOcVpYnyAAAABAFGQAAAJIoyAAAAJBEQQYAAIAkCjIAAAAkUZABAAAgiYIMAAAASZyDDLDc/PnzK7O77767OFvKzzzzzOJs6YzyiRMnFmeBsl133bUy+8EPflCc7devX2W2ZMmS4mzp/HPnHEPXs+666xbzH//4x61279JZxueee26r3ber8gQZAAAAoiADAABAEgUZAAAAkijIAAAAkERBBgAAgCQKMgAAACRxzBNAq3vXu95VzEeMGNFGK4GuZ9VVVy3m//Zv/1aZlY5xSpLXXnutMisd45Qk11xzTTHviLbYYotivmDBgsps1qxZLb0c6HA+8IEPVGa33XZbcXbttdcu5g0NDZXZY489VpzdeeedK7O//e1vxVneyhNkAAAAiIIMAAAASRRkAAAASKIgAwAAQBIFGQAAAJIoyAAAAJBEQQYAAIAkzkEGaHVNnX347//+7220Euh6dtlll2L+6U9/uu5rT5kypTL77//+77qvu7JKZ6tfcsklxdn3v//9ldnmm29enH311Vcrs/333784e+uttxZz6AgGDRpUzG+++ebKbK211irO1mq1Yr548eLK7Nhjjy3O/vnPfy7mvDOeIAMAAEAUZAAAAEiiIAMAAEASBRkAAACSKMgAAACQREEGAACAJI55AliudBzTzjvvXJzddtttK7Px48fXvaaV9fvf/74ymzdvXhuupPlKX+umjsy65pprKrMFCxbUvSbaV8+ePSuz//f//l/d1y0d2ZIk3/zmN+u+dms6+eSTK7OVOdaqKQMGDKjMPvnJTxZnHfNEZ3DmmWcW82HDhrXavY866qjKbMaMGa12X97KE2QAAACIggwAAABJFGQAAABIoiADAABAEgUZAAAAkijIAAAAkERBBgAAgCTOQQa6mF69qn9ZGz58eHH24osvrsy233774myPHtV/3rhs2bLibGvabbfdKrPf/e53xdnVV1+9rqwphxxySDHfYYcdKrMtt9yyOHvYYYdVZhdccEFx9qqrrirmtJ9dd921Mtt0003rvu7nP//5Yr548eK6r11SOk84Sc4444xiPmHChLrvXTr//KabbirONrV3oTP47ne/W5k19f94rVarzJ544oni7Omnn17Mf/CDHxRz2o4nyAAAABAFGQAAAJIoyAAAAJBEQQYAAIAkCjIAAAAkUZABAAAgiYIMAAAASZyD3K307NmzvZcAre7II4+szM4555w2XEnHsP/++1dmpfMck+QjH/lIXVlTSmdGJyt3bnTpnOSmzlB2DnLH1djYWPfsnXfeWZn95S9/qfu6Tenbt29lduWVVxZnS+eXN+W//uu/ivnJJ59cme2555513xc6is9+9rPF/D/+4z8qs4aGhuJs6Wz0b37zm8VZ5xx3Hp4gAwAAQBRkAAAASKIgAwAAQBIFGQAAAJIoyAAAAJBEQQYAAIAkjnnqVr761a8W86aOnYCOYOLEicX8S1/6UhutpHM45ZRTKrOVOU6po7r88ssrs9NPP70NV0JL2njjjSuzpUuXFmdLP+9Lliype01NWXPNNSuzlTnGKUn+3//7f5XZbbfdVpw9//zzK7OVWderr75a9yz8s9IxaUn5e4EJEyYUZ0tHHJaOcUqSY489tjK79NJLi7N0Hp4gAwAAQBRkAAAASKIgAwAAQBIFGQAAAJIoyAAAAJBEQQYAAIAkCjIAAAAkcQ4y0Mmcdtppxbwrnu3bEc2aNauYn3POOZVZQ0NDcbZ0RmVTrr322spswYIFdV+X9vXoo49WZptttllx9u67727p5SRJPvzhDxfziy66qFXu29S9jzzyyOLssGHDKrNFixYVZ//7v/+7MnPOOC3p3nvvLeabbLJJq9z3qKOOKubOOu4ePEEGAACAKMgAAACQREEGAACAJAoyAAAAJFGQAQAAIImCDAAAAEkc8wR0Moccckgxnzp1ahutZEU9enTMP28sresnP/lJcfbiiy+uzK6//vq61wQtafTo0cV88uTJldmgQYOKs2uuuWZlttVWWxVnS8cpraxdd921Va47YcKEYn7FFVe0yn3pnjbffPPKbNNNNy3OrsxxgIcffnhl5hgnEk+QAQAAIImCDAAAAEkUZAAAAEiiIAMAAEASBRkAAACSKMgAAACQREEGAACAJM5BBjqZps7uveOOOyqzHXbYoTi7cOHCymzevHnF2YaGhsqsqfMar7vu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1lqS2plnnvmOZ6Gz6Or7eqeddqolqa2++uq1E088sXbnnXfWLrzwwtqgQYNqo0ePrr366qvN/ryhs+jq+3qPPfaorb766rVXXnllhY+PHTu2lqT21a9+tclr0Dz+inU7mD59erbddtv0798/vXr1Su/evTN16tQ8/vjjb3ntjjvumLXWWmv5f/fs2TP77bdfZs+enWeffTZJctNNN2X77bfP0KFDs3Tp0uU/dtlllyTJXXfdVVzP7NmzM3v27CbX/cADD+Tcc8/NRRddlFVWWeWdfMrQ5XXWff3Ppk6dml69euXggw9+x7PQ1XTWfb1s2bIkyX777Zevfe1r2X777TNhwoRMnTo1s2fPzn/91381+2sAXU1n3ddHHnlk/va3v+XAAw/M73//+8ybNy+nnHJKfvnLXyaJf3/cgnwl29i1116bfffdN8OGDcuVV16Z++67Lw8++GDGjx+fhQsXvuX1a6+9duXHXnzxxSTJvHnzcuONN6Z3794r/Nhwww2TpMWOYBo/fnz22muvbLHFFpk/f37mz5+/fM0vv/xyXnnllRa5D3Q2nXlfv9kLL7yQG264IbvuuuvbrhG6k868rwcNGpQk2WmnnVb4+E477ZSGhoY8/PDDLXIf6Gw6877ecccdM23atNx9991pbGzM2muvnWuvvTann356kqzwb5NZOf4Nchu78sorM2rUqFx99dUrvHHGokWL3vb1c+fOrfzYP34DHDx4cDbaaKNMmTLlba/RUv/WaObMmZk5c2amT5/+lqyxsTEbb7xxHnnkkRa5F3QmnXlfv9kVV1yRxYsXe3MuSOfe1xtttFHxDHNPmuiuOvO+TpKDDjooBxxwQJ588sn07t07o0ePzplnnpmGhoaMHTu2xe7T3SnIbayhoSF9+vRZYVPOnTu38t3zfvazn2XevHnL/3rHG2+8kauvvjqNjY3Lj2bZbbfdcsstt6SxsTFrrLFGq619xowZb/nYZZddlssvvzzXXXedP7mi2+rM+/rNpk6dmqFDhy7/a2HQnXXmfb3nnnvm5JNPzq233po999xz+cdvvfXW1Go1b+RDt9WZ9/U/9OrVK+uvv36S5G9/+1suvvji7L777hkxYkSr37u7UJBbwZ133vm270T3iU98IrvttluuvfbaHH744dlnn33yzDPP5PTTT8+QIUPy5JNPvmVm8ODB2WGHHXLKKacsf/e8WbNmrfAnw5MnT87tt9+ebbbZJkcffXTWW2+9LFy4MHPmzMktt9ySCy+88C3nnL7Z6NGjk6TJf/+w3XbbveVjP//5z5Mk2267bQYPHlych86sq+7rf7j//vszc+bMnHTSSY5vo9voqvt6zJgxOeKII3LBBRdkwIAB2WWXXfLEE09k4sSJ2XTTTbPvvvs28ysEnU9X3dd/+ctf8o1vfCPbbrttBgwYkFmzZuXss89Ojx498p3vfKeZXx2apb3fJawr+ce751X9+MMf/lCr1Wq1s846qzZy5Mha3759a+uvv37tkksuWf5u0G+WpHbEEUfULrjgglpjY2Otd+/etTFjxtSuuuqqt9z7+eefrx199NG1UaNG1Xr37l0bOHBgbfPNN6+dfPLJtQULFqxwzX9+97wRI0bURowYUdfn7F2s6eq6y74+7LDDag0NDbWnnnqq2TPQWXWHfb106dLaWWedVRs9enStd+/etSFDhtQ+//nP1/7617++ky8VdBpdfV+/+OKLtY9//OO1Nddcs9a7d+/aOuusUzvqqKN8D94KGmq1Wq3V2jcAAAB0Et6lAQAAAKIgAwAAQBIFGQAAAJIoyAAAAJBEQQYAAIAkCjIAAAAkUZABAAAgSdKruS9saGhozXVAt9GRjh63r6Fl2NfQ9djX0PU0Z197ggwAAABRkAEAACCJggwAAABJFGQAAABIoiADAABAEgUZAAAAkijIAAAAkERBBgAAgCQKMgAAACRRkAEAACCJggwAAABJFGQAAABIoiADAABAEgUZAAAAkijIAAAAkERBBgAAgCQKMgAAACRRkAEAACCJggwAAABJFGQAAABIoiADAABAEgUZAAAAkiS92nsBAADdyciRI4v5nXfeWcxHjRpVmd10003F2U9+8pPFHKC78wQZAAAAoiADAABAEgUZAAAAkijIAAAAkERBBgAAgCQKMgAAACRxzBMAQIs78MADK7NTTjmlODt8+PBi/vLLL1dmt99+e3lhABR5ggwAAABRkAEAACCJggwAAABJFGQAAABIoiADAABAEgUZAAAAkijIAAAAkCRpqNVqtWa9sKGhtddCJzZz5szKbP311y/OHnXUUZXZd77znbrX1FE1c8u1CfsaWoZ93f28733vK+a33XZbZdazZ8/i7IknnljMr7nmmmJOy7Cvoetpzr72BBkAAACiIAMAAEASBRkAAACSKMgAAACQREEGAACAJAoyAAAAJEl6tfcC2tOXv/zlymyNNdYozp5xxhmV2SuvvFL3mrqipt5O/fe//30brQQAmu8973lPZfaTn/ykOPve9763MvvKV75SnHWME0D78QQZAAAAoiADAABAEgUZAAAAkijIAAAAkERBBgAAgCQKMgAAACRRkAEAACBJFz8HeeTIkcW8dA7ygAEDirPf/e53K7OueA5yr17l/1Waykt+/etf1z0LXUHPnj0rs1NOOaU429R5qg0NDZXZgw8+WJy98847K7PbbrutODtjxoxiDp3BAQccUJk1NjYWZ0t74Oyzz657TUD76dGj+tliKUuSvfbaq5hfffXVda0pSc4777zK7LTTTivOvvzyy5XZ0qVL615TZ+YJMgAAAERBBgAAgCQKMgAAACRRkAEAACCJggwAAABJFGQAAABIkjTUarVas15YOCqkozr00EOLeen4lOHDhxdnDznkkMrssssuK852RmuttVYxf+yxxyqz5557rji75ZZbVmaLFy8uL6wTauaWaxOdcV93RoMHDy7mW2yxRWV28803t/RyWsQzzzxTzJs6Zq+rsa87p/XWW6+Yl/bfqFGjirN77713ZXbdddcVZ+kY7OvOqXR0YpKsuuqqlVnpaLck2W677Sqz22+/vTg7efLkYr722msX89byq1/9qjIbO3ZscXbRokUtvZxW15x97QkyAAAAREEGAACAJAoyAAAAJFGQAQAAIImCDAAAAEkUZAAAAEiiIAMAAECSpFd7L6A1XXrppcX8F7/4RWU2c+bM4uzWW29dmXXFc5Bff/31uvPVVlutONunT5/KrCueg0zrGj16dGV2+OGHF2ff+973tvRykiQbbbRRMS+tuT099NBDlZlzXOkKjj/++GJeOuv44YcfLs4++OCDda2ptb373e+uzNZZZ53i7Pz58yuzZ599tt4lQYvaZ599ivmECRMqszXWWKM4W/r9+umnny7Onn322cX8qKOOqsyaOnd9ZWy++eaVWe/evYuznfEc5ObwBBkAAACiIAMAAEASBRkAAACSKMgAAACQREEGAACAJAoyAAAAJOnixzzRcl5++eVi/sorr1RmY8aMKc7279+/MluwYEF5YXQ7q666ajH/3ve+V5ltu+22Lb2cZpk1a1Yxv+222+q+9oc+9KFivvrqq1dmTR1JUfp6LV26tDgLHcXAgQMrsx133LHu655zzjnF/Lnnnqv72k1Zd911K7PSUTFJssUWW1RmW265ZXH2mWeeqcxKv/YmyZlnnlmZLVmypDgL78Sdd95ZzD/1qU9VZgceeGBxdu21167MSkcjNse8efMqs6uuumqlrs074wkyAAAAREEGAACAJAoyAAAAJFGQAQAAIImCDAAAAEkUZAAAAEiiIAMAAECSbn4O8i677FL3bFPnmgKtY+jQocV8jTXWqPvaP/nJTyqzps5VvOOOOyqzP/3pT8XZ559/vrywgnvuuaeYb7PNNpXZj3/84+Kss47pCg466KDKbMSIEcXZ0t5tau+VfPSjHy3mxxxzTDHfeuutK7OV+TWwKe9973srs0mTJhVnb7nllspsZc+Ppevp3bt3MS+dYV76vTxJDjjggLrWlCTPPvts3bNNWW211Vrt2rwzniADAABAFGQAAABIoiADAABAEgUZAAAAkijIAAAAkERBBgAAgCTd/JinVVddtb2X0Gn069evmPta0lbmzJlTzMeOHVuZDRgwoDg7b968ymzx4sXFWaB9vPvd7y7mX/jCF+q+9m9/+9vK7OWXXy7Onn/++ZXZfvvtV5wdNGhQeWEF06dPL+aXXnpp3dcuHa1z4oknFmd/9KMfVWYf+MAHirOvvPJKeWF0OcOGDSvmDQ0NbbSSltPUsXJf/OIX22glNMUTZAAAAIiCDAAAAEkUZAAAAEiiIAMAAEASBRkAAACSKMgAAACQREEGAACAJF38HOSmzuY94IAD6r526VzFpUuXFmevu+66yuyZZ56pd0mtao011qg7f+qpp4qzTZ0lCW/W1P6aP39+XVlHtc466xTz9773vXVfu0eP8p+R9unTp+5rt5YlS5YU81qt1kYroaPo3bt3MS+dp7pw4cLi7He+853K7NOf/nRx9vDDDy/mJX/961+L+THHHFOZ3XjjjcXZlfk9t3T27NFHH12cHT58eGW2ww47FGevv/768sLocubMmbNSeWvp379/ZXbaaacVZw8++OBivvrqq9exoqa99NJLxbzUS5r6NbKr8gQZAAAAoiADAABAEgUZAAAAkijIAAAAkERBBgAAgCQKMgAAACTp4sc8nXrqqcV8vfXWq/vapWMjzj333OLsOeecU5lde+21xdkTTjihMnvuueeKsyuj9Lb2STJgwIDK7De/+U1x9rXXXqtrTdDSVllllcpstdVWa7X7Dh48uDKbOHFicXZljnlq6liWpvLWsmjRospsgw02KM6219EftJ/x48fXPXvvvfcW89KxYhdeeGHd923qyLmDDjqomN98881133tl9OpV/W1jU8fGldxzzz11z9K+Sv9PNHVE6PPPP9/Sy1lpQ4YMKeYf/ehHK7Njjz22hVfTfI899lhl1tSRc039OtgdeYIMAAAAUZABAAAgiYIMAAAASRRkAAAASKIgAwAAQBIFGQAAAJIoyAAAAJCkC5yDvM8++1Rmxx9/fN3XPemkk4r5WWedVZntuuuuxdm99967Mvv0pz9dnN1///0rsxkzZhRnv/Od7xTzG264oTIrnXOXJA0NDcUcOoM99tijMrvyyivbbiGdQOl82CR58sknK7NrrrmmOHvXXXdVZs457p769etXmR133HF1X/fuu+8u5ldccUXd1y6ddfyZz3ymOHvrrbfWfd/WtM0221Rmffr0Kc5Onz69Mnv55ZfrXhPta+TIkZXZwIEDi7Oln/d3v/vdxdnSGcsbbrhhcbb068m4ceOKs3vuuWcxXxkvvvhiZfbFL36xOPujH/2oMnv99dfrXlN35QkyAAAAREEGAACAJAoyAAAAJFGQAQAAIImCDAAAAEkUZAAAAEiiIAMAAECSpKFWq9Wa9cIOes7tHXfcUZltv/32xdmnnnqqMttss82KswsWLCgvrE6bbLJJMS+dv7zddtsVZ3v37l3M//CHP1RmTZ15uu6661Zmv/zlL4uzY8eOLeZdTTO3XJvoqPu6vQwbNqwyu/jii4uzAwYMqPu+q666amW26aab1n3dJLnzzjsrs29/+9t1X3fhwoXFvPRrc1dkX7eu0v4qnTfclBdeeKGYDx48uO5rf+5zn6vMLrnkkrqv25qOP/74Yn766adXZk2dg7zxxhtXZo899lh5Ye3Evk569epVzA8//PDKrLQHkuTHP/5xZbb66qsXZ/faa6/K7D3veU9xtqT0vXCSjBo1qu5rl75WSXLvvfdWZh11j3RGzdnXniADAABAFGQAAABIoiADAABAEgUZAAAAkijIAAAAkERBBgAAgCRJ+b3bu7jLL7+8MmutY5ya8sgjjxTznXfeuTIrHaGQJPvuu28xHz9+fGW2Mm+ZP2TIkGLer1+/yuzVV1+t+77wTj333HOV2a677tpq991ggw0qs9/85jcrde2vfe1rlVl3O4qJzqt01OCsWbOKs2PGjKnMVuYYpx/96EfF/Ac/+EHd114Zw4cPL+YTJkyozJo65unZZ5+tzL7zne8UZ5v6eaJjaupInKFDh1Zm6623XnH2y1/+cl1rasoTTzxRzCdPnlyZHXzwwcXZv/71r5XZpZdeWpy96qqrinl7dQ/eyhNkAAAAiIIMAAAASRRkAAAASKIgAwAAQBIFGQAAAJIoyAAAAJBEQQYAAIAkXeAc5F/96leV2fz584uz5557bssupp09+uijK5Wffvrpldmvf/3r4uy6665bmTX1dS6dbwmUPfPMM8X8t7/9bRutBFrPwoULK7Of/vSnxdnSOchN+cMf/lCZffazny3Ovvrqq3Xftym77bZbZXbaaacVZzfZZJO671s667irfU/F3/XqVa4K73vf+9poJSsq7fsTTjihOPvYY49VZk2dX77aaqtVZm+88UZx1jnHnYcnyAAAABAFGQAAAJIoyAAAAJBEQQYAAIAkCjIAAAAkUZABAAAgSRc45ulLX/pSey+hyygdo7Eyx1XcdNNNxXzx4sV1Xxu6u0ceeaSY/+lPf2qbhUA7KR33uLL69etXmR144IF1X3f48OHFvKkjpAYOHFiZ9e7duzhbOrpqjz32KM7OmjWrmNP1LFq0qJh/8YtfrMx+8YtfFGdLRyY9/fTTxdkbb7yxMvvrX/9anN1oo40qs1VWWaU4e//99xdzugZPkAEAACAKMgAAACRRkAEAACCJggwAAABJFGQAAABIoiADAABAEgUZAAAAkiQNtVqt1qwXNjS09lrowB566KFivt5669WVJd3vnNZmbrk2YV+3jR49yn8Wedlll1VmBxxwQHF23LhxxbypcyhpGfZ1+xk0aFAx/8tf/tJGK+kYzjjjjGJ+zjnnVGYLFixo6eV0avZ157ThhhsW89JZ4E39fm2PdH7N2deeIAMAAEAUZAAAAEiiIAMAAEASBRkAAACSKMgAAACQREEGAACAJEmv9l4AHce73vWuyqxfv37F2d/97neVWXc7xgn+2Xve855i3tRRTiUd6RgSoHmuueaaYv773/++mF9xxRWVWen34yR54403ijl0dn/+85+L+WuvvdZGK6Gz8gQZAAAAoiADAABAEgUZAAAAkijIAAAAkERBBgAAgCQKMgAAACRRkAEAACCJc5B5k7XXXrsyW3fddYuz06ZNa+nlAECTXn/99WL+q1/9qjJbc801i7NN/d5Xr6bOIl62bFmr3Bc6kgEDBlRma621VnF29uzZldlLL71U95og8QQZAAAAkijIAAAAkERBBgAAgCQKMgAAACRRkAEAACCJggwAAABJHPPEm+y22251z5533nktuBLoWvbdd9/2XgJ0Wa+99lox33LLLdtoJcA7Udq7zz33XBuuBFbkCTIAAABEQQYAAIAkCjIAAAAkUZABAAAgiYIMAAAASRRkAAAASKIgAwAAQBLnIPMm++23X2V21llnFWcfe+yxll4OdBkjR45s7yUAQItbZZVVKrMJEyYUZ1955ZXKbOrUqXWvCVaWJ8gAAAAQBRkAAACSKMgAAACQREEGAACAJAoyAAAAJFGQAQAAIIljnniTsWPHtvcSAADoJD760Y9WZv379y/O9u3bt6WXAy3CE2QAAACIggwAAABJFGQAAABIoiADAABAEgUZAAAAkijIAAAAkERBBgAAgCRJQ61WqzXrhQ0Nrb0W6BaaueXahH3dNkaOHFnMn3rqqcrsueeeK842dX75008/XcxpGfY1dD32dTJgwIBi/tJLL1Vmf/7zn4uz66yzTl1rgpXRnH3tCTIAAABEQQYAAIAkCjIAAAAkUZABAAAgiYIMAAAASRRkAAAASOKYJ2hzjo2Arse+hq7HvoauxzFPAAAA0EwKMgAAAERBBgAAgCQKMgAAACRRkAEAACCJggwAAABJFGQAAABI8g7OQQYAAICuzBNkAAAAiIIMAAAASRRkAAAASKIgAwAAQBIFGQAAAJIoyAAAAJBEQQYAAIAkCjIAAAAkUZABAAAgiYIMAAAASRRkAAAASKIgAwAAQBIFGQAAAJIoyAAAAJBEQQYAAIAkCnKLuuyyy9LQ0JCHHnqoRa7X0NCQI488skWu9eZrnnrqqS1yrTvuuCMNDQ1paGjICy+80CLXhI6mO+zrJUuW5LTTTsvIkSPTt2/fjBkzJueff37LLRA6mK6+r0899dTlvz+/3Y8f/vCHLbpW6Ai6+r5OkieeeCJ777131lhjjay66qr50Ic+lBtuuKHlFkiSpFd7L4DOacGCBTnssMMydOjQ/OlPf2rv5QAr4fDDD88VV1yR008/Pf/yL/+S2267Lcccc0xeeeWVnHTSSe29POAdOvTQQ7Pzzju/5eOHHXZYnnrqqbfNgI5tzpw52XrrrTNkyJBceOGF6d+/f7773e9mjz32yPTp07P33nu39xK7DAWZunz5y1/OGmuskV133TVnnHFGey8HqNPMmTMzderUTJkyJSeccEKSZLvttsuLL76YM844I5/73OcycODAdl4l8E4MHz48w4cPX+Fjc+bMycyZM3PAAQdk9dVXb5+FAXU766yz8tprr+W2227LsGHDkiQ777xzPvjBD+YLX/hC9txzz/To4S8HtwRfxTa2cOHCHHfccdlkk02y2mqrZeDAgdl6661z/fXXV85cdNFFWXfdddO3b99ssMEGb/tXo+bOnZsJEyZk+PDh6dOnT0aNGpXTTjstS5cubfHP4Z577snFF1+cSy+9ND179mzx60Nn05n39XXXXZdarZbPfvazK3z8s5/9bF5//fX85Cc/abF7QWfSmff12/ne976XWq2WQw89tFXvAx1ZZ97X9957bzbeeOPl5ThJevbsmV122SXPPPNMHnjggRa7V3fnCXIbW7RoUV566aUcf/zxGTZsWBYvXpw77rgje+21V6ZNm5YDDzxwhdffcMMNmTFjRiZPnpx+/frlggsuyP77759evXpln332SfL3TbnlllumR48e+cpXvpLGxsbcd999OeOMMzJnzpxMmzatuKaRI0cm+fufLjfl9ddfzyGHHJJjjz02m222mX/3AOnc+/qxxx7LmmuumbXXXnuFj2+00UbLc+iOOvO+/mfLli3LZZddltGjR2fcuHHvaBa6ks68rxcvXvy2f6Orb9++SZL//d//zVZbbdXMrwRFNVrMtGnTaklqDz74YLNnli5dWluyZEntkEMOqW266aYrZElqq6yySm3u3LkrvH7MmDG10aNHL//YhAkTav379689/fTTK8x//etfryWpzZw5c4VrTpo0aYXXNTY21hobG5u13uOOO672vve9r/baa6/VarVabdKkSbUkteeff75Z89DZdPV9/bGPfay23nrrvW3Wp0+f2n/8x380eQ3obLr6vv5nt956ay1J7cwzz3zHs9BZdPV9vccee9RWX3312iuvvLLCx8eOHVtLUvvqV7/a5DVoHn/Fuh1Mnz492267bfr3759evXqld+/emTp1ah5//PG3vHbHHXfMWmuttfy/e/bsmf322y+zZ8/Os88+myS56aabsv3222fo0KFZunTp8h+77LJLkuSuu+4qrmf27NmZPXt2k+t+4IEHcu655+aiiy7KKqus8k4+ZejyOuu+Tv7+rpr1ZNDVdeZ9/WZTp05Nr169cvDBB7/jWehqOuu+PvLII/O3v/0tBx54YH7/+99n3rx5OeWUU/LLX/4ySfz74xbkK9nGrr322uy7774ZNmxYrrzyytx333158MEHM378+CxcuPAtr//nv/b45o+9+OKLSZJ58+blxhtvTO/evVf4seGGGyZJix3BNH78+Oy1117ZYostMn/+/MyfP3/5ml9++eW88sorLXIf6Gw6874eNGjQ8nu+2auvvlr517mgO+jM+/rNXnjhhdxwww3Zdddd33aN0J105n294447Ztq0abn77rvT2NiYtddeO9dee21OP/30JFnh3yazcvwb5DZ25ZVXZtSoUbn66qtXeDKzaNGit3393LlzKz82aNCgJMngwYOz0UYbZcqUKW97jaFDh67sspP8/d1uZ86cmenTp78la2xszMYbb5xHHnmkRe4FnUln3tcf/OAH88Mf/jBz585d4RuB3/zmN0mSD3zgAy1yH+hsOvO+frMrrrgiixcv9uZckM6/rw866KAccMABefLJJ9O7d++MHj06Z555ZhoaGjJ27NgWu093pyC3sYaGhvTp02eFTTl37tzKd8/72c9+lnnz5i3/6x1vvPFGrr766jQ2Ni4/wmG33XbLLbfcksbGxqyxxhqttvYZM2a85WOXXXZZLr/88lx33XX+5IpuqzPv69133z0TJ07M5Zdfni996UvLP37ZZZdllVVWcV4q3VZn3tdvNnXq1AwdOnT5X/eE7qwr7OtevXpl/fXXT5L87W9/y8UXX5zdd989I0aMaPV7dxcKciu488473/ad6D7xiU9kt912y7XXXpvDDz88++yzT5555pmcfvrpGTJkSJ588sm3zAwePDg77LBDTjnllOXvnjdr1qwV3mJ+8uTJuf3227PNNtvk6KOPznrrrZeFCxdmzpw5ueWWW3LhhRe+5TzENxs9enSSNPnvH7bbbru3fOznP/95kmTbbbfN4MGDi/PQmXXVfb3hhhvmkEMOyaRJk9KzZ8/8y7/8S37605/m4osvzhlnnOGvWNOlddV9/Q/3339/Zs6cmZNOOsmxjHQbXXVf/+Uvf8k3vvGNbLvtthkwYEBmzZqVs88+Oz169Mh3vvOdZn51aJb2fpewruQf755X9eMPf/hDrVar1c4666zayJEja3379q2tv/76tUsuuWT5u0G/WZLaEUccUbvgggtqjY2Ntd69e9fGjBlTu+qqq95y7+eff7529NFH10aNGlXr3bt3beDAgbXNN9+8dvLJJ9cWLFiwwjX/+d3zRowYURsxYkRdn7N3saar6w77evHixbVJkybV1llnnVqfPn1q6667bu288857R18n6Ey6w76u1Wq1ww47rNbQ0FB76qmnmj0DnVVX39cvvvhi7eMf/3htzTXXrPXu3bu2zjrr1I466ijfg7eChlqtVmu19g0AAACdhHexBgAAgCjIAAAAkERBBgAAgCQKMgAAACRRkAEAACCJggwAAABJkl7NfWFDQ0NrrgO6jY50spp9DS3Dvoaux76Grqc5+9oTZAAAAIiCDAAAAEkUZAAAAEiiIAMAAEASBRkAAACSKMgAAACQREEGAACAJAoyAAAAJFGQAQAAIImCDAAAAEkUZAAAAEiiIAMAAEASBRkAAACSKMgAAACQREEGAACAJAoyAAAAJFGQAQAAIImCDAAAAEkUZAAAAEiiIAMAAEASBRkAAACSKMgAAACQREEGAACAJAoyAAAAJFGQAQAAIImCDAAAAEkUZAAAAEiiIAMAAEASBRkAAACSKMgAAACQREEGAACAJAoyAAAAJFGQAQAAIImCDAAAAEkUZAAAAEiiIAMAAEASBRkAAACSJL3aewF0DqusskoxP//88yuzp556qjh75pln1rUmAACAluQJMgAAAERBBgAAgCQKMgAAACRRkAEAACCJggwAAABJFGQAAABI4pinuu20006V2ciRI4uzF110UQuvpvUNHDiwmI8fP74ymzRpUksvB7qUcePGVWZf+MIXirOf/OQn677vd77znWJ+9NFH131tAOD/rLvuusX8mGOOqXv2ox/9aGVWq9WKswsXLqzMttlmm+LsI488Usw7K0+QAQAAIAoyAAAAJFGQAQAAIImCDAAAAEkUZAAAAEiiIAMAAEASBRkAAACSOAe5bgsWLKjMzjvvvOLsr3/968rsgQceqHtNrWnLLbese/YXv/hFC64EOqZBgwZVZtOmTSvOfuQjH6nMBgwYUJxt6nzDkqbOUHYOMtRv8803r8xKez5JRowYUcyPOuqoutaUJPfcc09ltttuuxVnS9/7QHfQo0f1s8XPfOYzxdlJkyYV85EjR9azpCTJsmXL6p7t27dvZdbY2FicdQ4yAAAAdGEKMgAAAERBBgAAgCQKMgAAACRRkAEAACCJggwAAABJHPNUt4aGhsqsd+/exdlx48ZVZh31mKd99tmnmC9ZsqQye+mll1p6OdDmPvvZzxbzY489tjLbcMMNW3g1LWOttdYq5l/60pcqs6997WstvRy6uB133LEyGzhwYHH2U5/6VGU2f/784uyjjz5amR144IHF2aaOWyopHdH27ne/u+7rJit3vNvYsWMrs8cff7w4u/vuu1dmDz/8cN1rgo6iqWONLrjggsrsox/9aHH25ZdfLuaXXXZZZXb++ecXZ+++++7KrF+/fsXZa665pjIr/frZlXmCDAAAAFGQAQAAIImCDAAAAEkUZAAAAEiiIAMAAEASBRkAAACSKMgAAACQxDnIddtzzz3bewkt7l3veldltskmmxRnS+dQdtcz1Oh8PvOZz1Rm5513XnF2lVVWaenltLo+ffoU8ylTplRmr776anH2u9/9bmX2xhtvlBdGp1Q65zhJfvSjH1Vm/fv3r/u+DQ0NxXxlzgxeGaV1tdeamjJkyJBivvfee1dmzkGmsxgzZkxlNmnSpOJs6azjX/3qV8XZ//zP/yzmpe+1v//97xdnS7/efOMb3yjOnnLKKZXZokWLirNdlSfIAAAAEAUZAAAAkijIAAAAkERBBgAAgCQKMgAAACRRkAEAACCJY57qttVWW9U9++Mf/7gFV9JyPvCBD1Rm66+/fnF25syZLb0caHG77757Mb/88ssrs5U5lqV03SQZOXJkZbbddtvVfd/W9O1vf7uYl36de+6551p6OXQAAwcOLOYrc5QTHcMNN9zQ3kuAJpWOLU2Ss846qzLbaaedirOlI5OaOursjDPOKOaDBg2qzB555JHi7DHHHFOZzZgxozjLW3mCDAAAAFGQAQAAIImCDAAAAEkUZAAAAEiiIAMAAEASBRkAAACSKMgAAACQxDnIlVZbbbViXjoXuKlz0ObNm1fXmlrbDjvsUPesM9boKAYMGFCZHXvsscXZHj2q/8xw2bJlxdnSuYonn3xycbZ0rmJT+7KpdbWW0tcqSW688cbKbNdddy3O/vnPf65rTbSvRx99tJg//fTTldmIESNaejlAN/W1r32tmO+yyy6V2WGHHVac/f73v1+ZfexjHyvOTpkypZiXvpeeM2dOcZaW5QkyAAAAREEGAACAJAoyAAAAJFGQAQAAIImCDAAAAEkUZAAAAEjimKdKX/nKV4r56quvXpldeeWVxdnSsSxbbLFFcbZk5syZxfz111+v+9rQUWy++ebF/LrrrqvMhgwZUpwt7c0tt9yyOPub3/ymmJdMnjy5MnvooYeKs5/61Kfqvm9TNt5448psvfXWK85utNFGldnFF19cnP3kJz9ZXhgd0hNPPFHMd9xxx8rsyCOPLM6OGzeuMmvq983WOgrtrrvuKua//vWvK7PSnk+SW2+9tZh/6EMfKuYlK3OcXUNDQ933hZa0++67V2bjx48vzl500UWVWekYp6bcfvvtdc/SsXiCDAAAAFGQAQAAIImCDAAAAEkUZAAAAEiiIAMAAEASBRkAAACSKMgAAACQJGmo1Wq1Zr2wm519d++99xbzrbfeujJ76aWXirOl84iHDRtWXljBs88+W8yXLFlSzFdbbbXKbODAgcXZP/zhD5VZY2Njcba7aeaWaxOdcV//27/9WzFv6hzykq997WuV2WmnnVacXbx4cd337aiOPvroyuzYY48tzq6zzjqV2X333VecHTt2bDHviOzr1lX6/al///5tuJL/87e//a2YL1iwoDJ773vfW5z96U9/Wszf//73F/OS0v8fTf1/vO2221Zm999/f91r6qjs6/az5pprFvPSuevvfve7i7Mf//jHK7Of/exn5YW1on79+lVmTX3vUzpn/uyzzy7OPvLII8W8q2nOvvYEGQAAAKIgAwAAQBIFGQAAAJIoyAAAAJBEQQYAAIAkCjIAAAAkSXq19wI6qqFDh9Y929SRSPPmzavMZs6cWZx97LHH6lpTkmy//fbFvKl1l7zxxht1z8I/22qrrSqz8847rzhb+n/xwgsvLM6efPLJ5YV1M6Wvdem4uiT5z//8z8ps3XXXLc6Wfv7/53/+pzhL11Q6Uqmp45Y6oqaObFmZY5xWxp133lnMm/oeBVpKU9+zlo5yuuuuu4qzd999d11rWlm9e/cu5t///vcrsz322KPu+15++eV1z3ZXniADAABAFGQAAABIoiADAABAEgUZAAAAkijIAAAAkERBBgAAgCQKMgAAACRxDnKlbbfdtpivscYadV+7dA7yCy+8UPd1m7LZZpsV84ceeqgyW7BgQXF2r732qmtN8HaOOOKIyqyp87qfeeaZyuyYY46pe02s6JJLLinmEydOrMyGDRtWnB0+fHhda4LO4sgjj2zvJbytp556qpg39b0AtJTDDjus7tlzzz23mC9ZsqTua/foUf1scaeddirONnUe8aBBg+paU1PXvu222+q+bnflCTIAAABEQQYAAIAkCjIAAAAkUZABAAAgiYIMAAAASRRkAAAASKIgAwAAQBLnIFf605/+tFJ5R/ShD32o7tlrrrmmmD/22GN1Xxv+2bhx4yqzhoaG4uw999zT0suhDqWfp6Z+DoH2ccYZZ7T3EqBdDRkypJh/6lOfqswuuOCCll7Ocr///e+L+amnntpq9+6OPEEGAACAKMgAAACQREEGAACAJAoyAAAAJFGQAQAAIImCDAAAAEkc89StrL766nXPzp8/v8XWAU2ZPHlyZXbYYYcVZydMmNDSy6EOtVqtrgy6is0337wyGzBgQHG2NY9C69HDsxE6vr/+9a91z37hC18o5mPHjq3MjjnmmOJsz54961pTcyxevLgyO+CAA4qzf/zjH1t6Od2aXyUBAAAgCjIAAAAkUZABAAAgiYIMAAAASRRkAAAASKIgAwAAQBIFGQAAAJI4B5lm+tnPftbeS6AbOfDAAyuz0jmBSfL666+39HIA3rGPfOQjldm73/3u4mxrnhU+a9asysyvn3QU3/jGN4r5Jz/5ycqstPeak7eXb37zm5XZAw880IYrwRNkAAAAiIIMAAAASRRkAAAASKIgAwAAQBIFGQAAAJIoyAAAAJDEMU/dSt++feueffHFF1twJVA2YsSIyuyPf/xjG66E1rBo0aJi/uqrr7bRSqD1lH4da08333xzZfbSSy+14Uqg2v3331/MJ0+eXJkddthhxdlf//rXldn1119fnN19990rsz322KM4u2DBgmL+4x//uJjTdjxBBgAAgCjIAAAAkERBBgAAgCQKMgAAACRRkAEAACCJggwAAABJFGQAAABI4hzkLqVnz57FfO+99y7mpfMP586dW9eagK5p3LhxxXy11VarzB5++OHi7K233lrXmqAtrb766sX8qKOOqsxqtVoLr6b5Xn755Xa7N7SUM888s66sKR/4wAeK+X/+53/Wfe2DDz64mD/00EN1X5uW5QkyAAAAREEGAACAJAoyAAAAJFGQAQAAIImCDAAAAEkUZAAAAEjimKcuZf311y/mG264YTE/55xzKrM5c+bUsySoywknnFCZ/eAHPyjO7rPPPpXZNddcU/eauqPSUU4///nPi7PLli2rzEo/v9BZTJw4sb2XUJfJkye39xKgXb3rXe+qzC655JLibL9+/Sqz+++/vzh78803lxdGh+EJMgAAAERBBgAAgCQKMgAAACRRkAEAACCJggwAAABJFGQAAABIoiADAABAEucgdyl77bVXMW9oaCjmb7zxRksuB+r2xz/+sTL73e9+V5zddNNNK7P2Ogd51VVXLea77rprZTZ9+vSVuvegQYMqs6Z+zSidjf7rX/+6OHvjjTdWZg8//HBxFjqDpn5P7dGj+hlE6ZzwlXXccce12rWhK/jUpz5VmW255ZbF2VqtVpk1dcb44sWLywujw/AEGQAAAKIgAwAAQBIFGQAAAJIoyAAAAJBEQQYAAIAkCjIAAAAkccxTp7PxxhtXZqWjYpLk5ZdfLuYXX3xxXWuClvY///M/ldkuu+xSnH366afrvu/QoUMrs6OOOqo4e/3111dmhx56aHH24IMPrsw222yzuu+bJCeddFJl9olPfKI4W3L22WcX85/97GeVmaMu6ApKx70k5aOcmpoF6tezZ89iPnHixLqv/frrr1dmP/nJT+q+Lh2LJ8gAAAAQBRkAAACSKMgAAACQREEGAACAJAoyAAAAJFGQAQAAIImCDAAAAEmcg9zpHHvssZXZv/zLvxRnjzjiiGI+Z86cOlYEbWtlzjluSuks8dmzZxdnt99++8qsdM5xUz7/+c8X88997nPFfP78+ZXZlClTirO/+c1vKrNrrrmmOAsA7eHAAw8s5htuuGFl9rvf/W6lrk3X4AkyAAAAREEGAACAJAoyAAAAJFGQAQAAIImCDAAAAEkUZAAAAEjimKdO57Of/WxdGdC0Sy65pO7ZIUOGVGZ9+/Ytzk6cOLEyu/TSS+teU5Icf/zxKzUPdDwvvvhiZXbTTTe14UqgffTr168yO+aYY+q+7rx584r5Qw89VPe16Tw8QQYAAIAoyAAAAJBEQQYAAIAkCjIAAAAkUZABAAAgiYIMAAAASRRkAAAASJI01Gq1WrNe2NDQ2muBbqGZW65N2NfQMuzr7mfcuHHF/M4776zMmvr/Zc6cOcX8zDPPrMymTp1anKX57Gvoepqzrz1BBgAAgCjIAAAAkERBBgAAgCQKMgAAACRRkAEAACCJggwAAABJHPMEbc6xEdD12NfQ9djX0PU45gkAAACaSUEGAACAKMgAAACQREEGAACAJAoyAAAAJFGQAQAAIImCDAAAAEnewTnIAAAA0JV5ggwAAABRkAEAACCJggwAAABJFGQAAABIoiADAABAEgUZAAAAkijIAAAAkERBBgAAgCQKMgAAACRJ/j+P/uemHboQhgAAAABJRU5ErkJggg==",
      "text/plain": [
       "<Figure size 1000x1000 with 16 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "\n",
    "# Get 16 random indices\n",
    "indices = np.random.choice(len(train_dataset), size=16, replace=False)\n",
    "\n",
    "# Get the corresponding images and labels\n",
    "images = [train_dataset[i][0] for i in indices]\n",
    "labels = [train_dataset[i][1] for i in indices]\n",
    "\n",
    "# Create a figure with 4x4 subplots\n",
    "fig, axes = plt.subplots(4, 4, figsize=(10, 10))\n",
    "\n",
    "# Iterate over the subplots and display the images with labels\n",
    "for i, ax in enumerate(axes.flat):\n",
    "    ax.imshow(images[i].squeeze(), cmap='gray')\n",
    "    ax.set_title(f\"Label: {labels[i]}\")\n",
    "    ax.axis('off')\n",
    "\n",
    "# Adjust the spacing between subplots\n",
    "plt.tight_layout()\n",
    "\n",
    "# Show the figure\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Build an MLP Model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "MLP(\n",
      "  (fc1): Linear(in_features=784, out_features=128, bias=True)\n",
      "  (relu): ReLU()\n",
      "  (fc2): Linear(in_features=128, out_features=10, bias=True)\n",
      ")\n",
      "torch.Size([64, 10])\n",
      "Number of parameters: 101,770\n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    "import torch.nn as nn\n",
    "\n",
    "class MLP(nn.Module):\n",
    "    def __init__(self, input_size=28*28, hidden_size=128, num_classes=10):\n",
    "        super(MLP, self).__init__()\n",
    "        self.fc1 = nn.Linear(input_size, hidden_size)\n",
    "        self.relu = nn.ReLU()\n",
    "        self.fc2 = nn.Linear(hidden_size, num_classes)\n",
    "    \n",
    "    def forward(self, x):\n",
    "        x = x.view(x.size(0), -1)  # Flatten the input tensor\n",
    "        y = self.fc1(x)\n",
    "        y = self.relu(y)\n",
    "        y = self.fc2(y)\n",
    "        \n",
    "        return y\n",
    "\n",
    "# Create an instance of the MLP model\n",
    "model = MLP()\n",
    "x = torch.randn(64, 1, 28, 28)\n",
    "print(model)\n",
    "print(model(x).shape)\n",
    "\n",
    "# print the number of parameters\n",
    "num_params = sum(p.numel() for p in model.parameters())\n",
    "# Use comma to print the number in a more readable format\n",
    "print(f\"Number of parameters: {num_params:,}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Define the loss function and optimizer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n",
    "model.to(device)\n",
    "\n",
    "# Define the loss function and optimizer\n",
    "criterion = nn.CrossEntropyLoss()\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=0.001)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Train the model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " 10%|█         | 1/10 [00:08<01:13,  8.22s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 1, Loss: 0.3837\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " 20%|██        | 2/10 [00:16<01:04,  8.09s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 2, Loss: 0.1938\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " 30%|███       | 3/10 [00:24<00:56,  8.04s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 3, Loss: 0.1367\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " 40%|████      | 4/10 [00:32<00:48,  8.09s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 4, Loss: 0.1123\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " 50%|█████     | 5/10 [00:40<00:40,  8.04s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 5, Loss: 0.0964\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " 60%|██████    | 6/10 [00:48<00:32,  8.02s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 6, Loss: 0.0829\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " 70%|███████   | 7/10 [00:56<00:23,  8.00s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 7, Loss: 0.0755\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " 80%|████████  | 8/10 [01:04<00:16,  8.06s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 8, Loss: 0.0654\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " 90%|█████████ | 9/10 [01:12<00:08,  8.03s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 9, Loss: 0.0633\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████| 10/10 [01:20<00:00,  8.04s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 10, Loss: 0.0552\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    }
   ],
   "source": [
    "from tqdm import tqdm\n",
    "\n",
    "num_epochs = 10\n",
    "\n",
    "model.train()\n",
    "for epoch in tqdm(range(num_epochs)):\n",
    "    total_loss = 0\n",
    "    \n",
    "    for images, labels in train_loader:\n",
    "        images = images.to(device)\n",
    "        labels = labels.to(device)\n",
    "        \n",
    "        # Forward pass\n",
    "        outputs = model(images)\n",
    "        loss = criterion(outputs, labels)\n",
    "        \n",
    "        # Backward and optimize\n",
    "        optimizer.zero_grad()\n",
    "        loss.backward()\n",
    "        optimizer.step()\n",
    "        \n",
    "        total_loss += loss.item()\n",
    "    \n",
    "    avg_loss = total_loss / len(train_loader)\n",
    "    print(f\"Epoch: {epoch+1}, Loss: {avg_loss:.4f}\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Evaluate the model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Test Accuracy: 0.9744\n"
     ]
    }
   ],
   "source": [
    "model.eval()  # Set the model to evaluation mode\n",
    "\n",
    "correct = 0\n",
    "total = 0\n",
    "\n",
    "with torch.no_grad():\n",
    "    for images, labels in test_loader:\n",
    "        images = images.to(device)\n",
    "        labels = labels.to(device)\n",
    "        \n",
    "        # Forward pass\n",
    "        outputs = model(images)\n",
    "        _, predicted = torch.max(outputs.data, 1)\n",
    "        \n",
    "        total += labels.size(0)\n",
    "        correct += (predicted == labels).sum().item()\n",
    "\n",
    "accuracy = correct / total\n",
    "print(f\"Test Accuracy: {accuracy:.4f}\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Predict on sample images"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYUAAAGZCAYAAABmNy2oAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAAA9hAAAPYQGoP6dpAAAVO0lEQVR4nO3ce5CWdfn48WuFZRFPuXJQIQ4umVqpSKKgZYCGCgyW6GiZlJh4zhkSKxMEsSHRJocBcTTxmMcoRElHOZWOjmXmHxqTzohjkzAIlKCIQJ/fH9+4fq4sh3s5Kb1eM/sHz97XfX+eZ3efN/c+z941pZQSABARu+3sBQDwySEKACRRACCJAgBJFABIogBAEgUAkigAkEQBgCQKnyJ33nln1NTUxJ///Odtsr+ampq49NJLt8m+PrrPa6+9tlmzL774YlxyySXxpS99Kfbaa6/o0KFDnHjiiTFnzpytXtNHP/bZZ5/42te+Fo8//vhW7XdLXXvttVFTU9Potq5du8Z3v/vdSvt5//3349prr4158+Ztu8X917x586KmpqbZ+7799tvjtNNOi65du8buu+8e3bt3j4suuijefvvtbbtQtjtR4BPj/vvvjxdeeCHOO++8mDFjRtx+++1RV1cX/fv3j7vvvnur9j106NB47rnn4tlnn43JkyfHokWLYvDgwTssDB/329/+Nq655ppKM++//36MHTt2u0Rha40ZMyb23HPP+NnPfhZPPPFEjBo1Kh577LHo2bNnLF68eGcvjwpa7uwFwHqjRo2KG2+8sdFtp556ahx11FExbty4OPfcc5u97w4dOsSxxx4bERF9+vSJ3r17R/fu3eOXv/xlDBw4sMmZNWvWRE1NTbRsue1/THr06LHN97kzvfTSS9G+ffv89wknnBBHHXVUHH300XHbbbfFT3/60524OqpwprCL+eCDD2LkyJFx5JFHxj777BP19fXRu3fvmDFjxkZnbr311jj44IOjrq4uDjvssHjggQc22GbRokUxYsSI6NSpU7Rq1Sq6desWY8eOjbVr126ztX/0SWW9Fi1aRM+ePeOtt97aZseJiGhoaIh27drFm2++GRH//9cn99xzT4wcOTI6duwYdXV18frrr0dExNNPPx39+/ePvffeO9q0aRPHHXdczJ49e4P9Pv7443HkkUdGXV1ddOvWbYPIrdfUr4/+9a9/xciRI+Oggw6Kurq6aN++fZx66qmxYMGCWLhwYbRr1y4iIsaOHZu/CvvoPl577bX41re+Fe3bt4+6uro49NBDY/LkyRsce8GCBXHyySdHmzZtom3btnHhhRfGihUrmvMwpqa+dj179owWLVps868d25czhV3M6tWrY9myZfHDH/4wOnbsGB9++GE8/fTT8c1vfjOmTZu2wf+2H3300Zg7d26MGzcu9thjj5gyZUqcffbZ0bJlyxg6dGhE/F8QevXqFbvttluMHj06Ghoa4rnnnovx48fHwoULY9q0aZtcU9euXSMiYuHChZXvz9q1a+OPf/xjfOELX6g8uynLly+PpUuXxuc+97lGt//4xz+O3r17x9SpU2O33XaL9u3bx7333hvnnntuDBkyJO66666ora2NW2+9NQYMGBBPPvlk9O/fPyIiZs+eHUOGDInevXvHAw88EOvWrYsbbrhhi359smLFijj++ONj4cKFcdVVV8UxxxwTK1eujD/84Q/x9ttvR58+feKJJ56Ik08+OYYPHx7nn39+RESG4tVXX40+ffpE586d46abbor9998/nnzyybj88svjnXfeiTFjxkRExOLFi+OEE06I2tramDJlSnTo0CHuu+++Jl9bmjdvXvTt2zfGjBnTrNeJ5s+fH+vWrdvmXzu2s8KnxrRp00pElD/96U9bPLN27dqyZs2aMnz48NKjR49Gn4uIsvvuu5dFixY12v6QQw4p3bt3z9tGjBhR9txzz/Lmm282mr/xxhtLRJRXXnml0T7HjBnTaLuGhobS0NCwxWv+qKuvvrpERPnd737XrPn1a7r44ovLmjVryocfflj+9re/lVNOOaVERJk8eXIppZS5c+eWiChf/epXG82+9957pb6+vgwePLjR7evWrStHHHFE6dWrV952zDHHlAMPPLCsWrUqb3v33XdLfX19+fiPWpcuXcqwYcPy3+PGjSsRUZ566qmN3o8lS5Y0+fiWUsqAAQNKp06dyr///e9Gt1966aWldevWZdmyZaWUUq666qpSU1NT/vrXvzba7qSTTioRUebOnZu3zZs3r7Ro0aKMHTt2o2vamHfffbcceuih5bOf/WxZsWJF5Xl2HlH4FNnSKDz00EOlT58+ZY899igRkR+tW7dutF1ElEGDBm0wP2bMmBIR5a233iqllNKxY8cyePDgsmbNmkYfr7zySomIMmXKlEb7bOpJqzluu+22EhFl5MiRW7Wfjz4G6z/22WefMm7cuNxmfRRuvvnmRrNPPfVUiYjyyCOPbHD/1z/Brly5sqxcubLstttu5dJLL93g+MOGDdtsFHr37l0OPvjgTd6PjUVh1apVpWXLluWyyy7bYI2zZs0qEVFmzZpVSimlV69e5Ytf/OIG+17/vfXRKDTXqlWryoknnljatGlTnn/++a3eHzuWXx/tYqZPnx5nnnlmnHHGGXHllVfG/vvvHy1btoxbbrkl7rjjjg2233///Td629KlS6NTp06xePHimDlzZtTW1jZ5zHfeeWfb3omImDZtWowYMSIuuOCCmDhx4lbv78wzz4wrr7wyampqYq+99oqGhoZo0aLFBtsdcMABjf69/lc/63+V1pRly5ZFTU1N/Oc//9nk47kpS5Ysic6dO292u6YsXbo01q5dG5MmTYpJkyY1uc36r9HSpUujW7duzVrjlli9enV84xvfiGeeeSYee+yxOOaYY7bJftlxRGEXc++990a3bt3iwQcfbPTe+NWrVze5/aJFizZ623777RcREW3bto3DDz88rr/++ib3ceCBB27tshuZNm1anH/++TFs2LCYOnXqBu/xb4527drFl7/85c1u9/FjtW3bNiIiJk2alO9e+rgOHTrkO5U29Xhubn3/+Mc/NrtdU/bdd99o0aJFfOc734lLLrmkyW3Wh2C//fZr9ho3Z/Xq1XHaaafF3LlzY8aMGflaC58uorCLqampiVatWjV6clu0aNFG3300e/bsWLx4cXTo0CEiItatWxcPPvhgNDQ0RKdOnSIiYtCgQTFr1qxoaGiIfffdd7uu/84774zzzz8/zjnnnLj99tu3SRC2xnHHHRef+cxn4tVXX93kH/q1atUqevXqFdOnT4+JEydG69atI+L/XkCeOXPmZo9zyimnxOjRo2POnDnRr1+/Jrepq6uLiIhVq1Y1ur1NmzbRt2/feOmll+Lwww+PVq1abfQ4ffv2jRtuuCFefvnlOOKII/L2X//615td46asP0OYM2dOTJ8+PQYMGLBV+2PnEYVPoTlz5jT5Tp5TTz01Bg0aFNOnT4+LL744hg4dGm+99VZcd911ccABB8Rrr722wUzbtm2jX79+cc011+S7jxYsWNDobanjxo2Lp556Kvr06ROXX355fP7zn48PPvggFi5cGLNmzYqpU6dmQJrSvXv3iIh8e+fGPPzwwzF8+PA48sgjY8SIEfHCCy80+nyPHj3yiXFr3xmzpfbcc8+YNGlSDBs2LJYtWxZDhw6N9u3bx5IlS+Lll1+OJUuWxC233BIREdddd12cfPLJcdJJJ8XIkSNj3bp18fOf/zz22GOPWLZs2SaPc8UVV8SDDz4YQ4YMiR/96EfRq1evWLVqVcyfPz8GDRoUffv2jb322iu6dOmS/wuvr6+Ptm3bRteuXePmm2+O448/Pr7yla/ERRddFF27do0VK1bE66+/HjNnzsy/Cr/iiivijjvuiIEDB8b48ePz3UcLFizYYE3z58+P/v37x+jRo2P06NGbXP/QoUPj97//fVx99dWx3377xfPPP5+f23vvveOwww6r+tCzs+zsFzXYcutfDNzYxxtvvFFKKWXChAmla9eupa6urhx66KHltttuyxePPyoiyiWXXFKmTJlSGhoaSm1tbTnkkEPKfffdt8GxlyxZUi6//PLSrVu3UltbW+rr60vPnj3L1VdfXVauXNlonx9/IbRLly6lS5cum71/61+Q3dz9K6WUmTNnlogoU6dO3ex+19/PTVn/QvPDDz/c5Ofnz59fBg4cWOrr60ttbW3p2LFjGThw4AbbP/roo+Xwww8vrVq1Kp07dy4TJkxo8rH/+AvNpZSyfPny8oMf/KB07ty51NbWlvbt25eBAweWBQsW5DZPP/106dGjR6mrqysR0Wgfb7zxRjnvvPNKx44dS21tbWnXrl3p06dPGT9+fKPjvPrqq+Wkk04qrVu3LvX19WX48OFlxowZG7zQvP4x2ZI3Dmzq63bCCSdsdp5PjppSStkB7YFtatSoUXH//ffHa6+9lr+qAbaev2jmU2nu3LlxzTXXCAJsY84UAEjOFABIogBAEgUAkigAkLb4j9d29l+WArB1tuR9Rc4UAEiiAEASBQCSKACQRAGAJAoAJFEAIIkCAEkUAEiiAEASBQCSKACQRAGAJAoAJFEAIIkCAEkUAEiiAEASBQCSKACQRAGAJAoAJFEAIIkCAEkUAEiiAEASBQCSKACQRAGAJAoAJFEAIIkCAEkUAEiiAEASBQCSKACQRAGAJAoAJFEAIIkCAEkUAEiiAEASBQCSKACQRAGAJAoAJFEAIIkCAEkUAEiiAEASBQCSKACQWu7sBbDzXXjhhZVnbrrppu2wkqY98sgjlWfuu+++yjPz58+vPLN69erKM/BJ5kwBgCQKACRRACCJAgBJFABIogBAEgUAkigAkEQBgCQKACRRACCJAgCpppRStmjDmprtvRZ2krvuuqvyzDnnnLMdVrLtNOf79Yknnqg8c/3111eeefbZZyvPwLawJU/3zhQASKIAQBIFAJIoAJBEAYAkCgAkUQAgiQIASRQASKIAQBIFAJIoAJBcEI8466yzKs/069ev8sywYcMqz0REtGzZsvJMc75ft/BHoZG1a9dWnpk0aVLlmYjmXXxv+fLlzToWuyYXxAOgElEAIIkCAEkUAEiiAEASBQCSKACQRAGAJAoAJFEAIIkCAEkUAEguiMcO07dv32bNNedCescff3zlmW7dulWe2ZGWLVtWeebggw+uPOMiersuF8QDoBJRACCJAgBJFABIogBAEgUAkigAkEQBgCQKACRRACCJAgBJFABIogBAcpVU+K/HH3+88swpp5yyHVay7Vx55ZWVZ2666abtsBI+CVwlFYBKRAGAJAoAJFEAIIkCAEkUAEiiAEASBQCSKACQRAGAJAoAJFEAILXc2QuAT4rTTjut8sy5555beaZfv36VZyIizj777GbNQRXOFABIogBAEgUAkigAkEQBgCQKACRRACCJAgBJFABIogBAEgUAkigAkFwQD/5rzZo1lWd+9atfVZ758MMPK89EuCAeO4YzBQCSKACQRAGAJAoAJFEAIIkCAEkUAEiiAEASBQCSKACQRAGAJAoAJBfEgx3soIMO2tlLgI1ypgBAEgUAkigAkEQBgCQKACRRACCJAgBJFABIogBAEgUAkigAkEQBgCQKACRXSYWtUFdXV3lm8ODB22ElTfvnP/+5w47FrsGZAgBJFABIogBAEgUAkigAkEQBgCQKACRRACCJAgBJFABIogBAEgUAkgviwVbo169f5ZkePXo061h///vfK888+uijzToW/7ucKQCQRAGAJAoAJFEAIIkCAEkUAEiiAEASBQCSKACQRAGAJAoAJFEAILkgHvxXbW1t5Zmf/OQn22ElTZs8eXLlmffee287rIRdmTMFAJIoAJBEAYAkCgAkUQAgiQIASRQASKIAQBIFAJIoAJBEAYAkCgAkF8SD//rFL35ReaZPnz7bYSVN+8tf/rLDjsX/LmcKACRRACCJAgBJFABIogBAEgUAkigAkEQBgCQKACRRACCJAgBJFABILojHLunrX/965Znzzjuv8kxNTU3lmQEDBlSeiYh49tlnmzUHVThTACCJAgBJFABIogBAEgUAkigAkEQBgCQKACRRACCJAgBJFABIogBAEgUAUk0ppWzRhs24GiR8VPv27Zs19+1vf7vyzPjx4yvPtG7duvJMcyxfvrxZc2vWrNkhx5o4cWLlmUceeaTyzIoVKyrPsHW25OnemQIASRQASKIAQBIFAJIoAJBEAYAkCgAkUQAgiQIASRQASKIAQBIFAJIL4hF1dXWVZ0aNGlV55oILLqg8ExFx4IEHVp5pzvfrFv4o7DSf5Ps0e/bsyjNDhgxp1rFWrVrVrDlcEA+AikQBgCQKACRRACCJAgBJFABIogBAEgUAkigAkEQBgCQKACRRACC5IN4u5qCDDqo8M2HChMozp59+euWZHak5368PPfRQ5Znf/OY3lWfq6+srz0Q07zHv379/s461I9x9993Nmvve9763jVfyv8MF8QCoRBQASKIAQBIFAJIoAJBEAYAkCgAkUQAgiQIASRQASKIAQBIFAJIL4n1C1dXVNWvunnvuqTxzxhlnVJ7Zwm+bbeLFF1+sPHP00Udvh5V8+vTs2bPyzMiRIyvPnHXWWZVn3n777cozEc27yN+CBQuadaxdjQviAVCJKACQRAGAJAoAJFEAIIkCAEkUAEiiAEASBQCSKACQRAGAJAoApJY7ewE07fvf/36z5k4//fTKM825uN17771XeWbChAmVZyIiJk6c2Kw5mncxwcsuu6zyTNeuXSvPHHvssZVnIiIGDhxYecYF8bacMwUAkigAkEQBgCQKACRRACCJAgBJFABIogBAEgUAkigAkEQBgCQKACRRACC5SiqxevXqyjP3339/5Znrr7++8gw73tKlSyvPNOfKql/96lcrz0RE3Hvvvc2aY8s4UwAgiQIASRQASKIAQBIFAJIoAJBEAYAkCgAkUQAgiQIASRQASKIAQKoppZQt2rCmZnuvhY+oq6tr1twzzzxTeebhhx+uPHPDDTdUngF2ri15unemAEASBQCSKACQRAGAJAoAJFEAIIkCAEkUAEiiAEASBQCSKACQRAGA5IJ4AP8jXBAPgEpEAYAkCgAkUQAgiQIASRQASKIAQBIFAJIoAJBEAYAkCgAkUQAgiQIASRQASKIAQBIFAJIoAJBEAYAkCgAkUQAgiQIASRQASKIAQBIFAJIoAJBEAYAkCgAkUQAgiQIASRQASKIAQBIFAJIoAJBEAYAkCgAkUQAgiQIASRQASKIAQBIFAJIoAJBEAYAkCgAkUQAgiQIASRQASKIAQBIFAJIoAJBEAYAkCgAkUQAgtdzSDUsp23MdAHwCOFMAIIkCAEkUAEiiAEASBQCSKACQRAGAJAoAJFEAIP0/ezX5w4qo4doAAAAASUVORK5CYII=",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import random\n",
    "\n",
    "# Set the model to evaluation mode\n",
    "model.eval()\n",
    "\n",
    "# Select a random image from the test dataset\n",
    "random_index = random.randint(0, len(test_dataset) - 1)\n",
    "image, label = test_dataset[random_index]\n",
    "\n",
    "# Move the image to the device\n",
    "image = image.to(device)\n",
    "\n",
    "# Forward pass to get the predicted label\n",
    "output = model(image.unsqueeze(0))\n",
    "_, predicted_label = torch.max(output, 1)\n",
    "\n",
    "# Convert the image tensor to a numpy array\n",
    "image_np = image.cpu().numpy()\n",
    "\n",
    "# Display the image, its label, and the predicted label\n",
    "plt.imshow(image_np.squeeze(), cmap='gray')\n",
    "plt.title(f\"Label: {label}, Predicted: {predicted_label.item()}\")\n",
    "plt.axis('off')\n",
    "plt.show()\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "base",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
